package com.zzj.controller;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zzj.annotation.LogAnnotation;
import com.zzj.base.Result;
import com.zzj.entity.Post;
import com.zzj.entity.User;
import com.zzj.model.dto.QueryListDto;
import com.zzj.model.dto.user.UserUpdateDto;
import com.zzj.model.dto.mail.EmailLoginDto;
import com.zzj.model.dto.user.ForgetDto;
import com.zzj.model.dto.user.LoginDto;
import com.zzj.model.dto.user.RegisterDto;
import com.zzj.model.dto.websocket.WxLoginDto;
import com.zzj.service.IUserService;
import com.zzj.service.RedisService;
import com.zzj.service.WebSocketService;
import com.zzj.utils.JWTUtil;
import com.zzj.utils.RSAUtil;
import com.zzj.utils.WechatUtil;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author zzj
 * @since 2023-07-17
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;
    @Resource
    private RedisService redisService;
    @Resource
    private WechatUtil wechatUtil;
    @Resource
    private WebSocketService webSocketService;


    @LogAnnotation(name = "用户名密码登录", description = "用户名密码登录")
    @Transactional
    @PostMapping("/login")
    public Result<?> login(@RequestBody LoginDto in) throws Exception {
        User byUsername = userService.findByUsername(in.getUsername());
        if (byUsername != null && byUsername.getPassword().equals(DigestUtil.md5Hex(RSAUtil.decrypted(in.getPassword())))) {
            byUsername.setPassword("*");
            String token = JWTUtil.generateToken(byUsername);
            String refreshToken = UUID.randomUUID().toString();
            redisService.setRefreshToken(token, refreshToken, in.getUsername());
            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            map.put("refreshToken", refreshToken);
            map.put("userInfo", byUsername);
            return Result.success("登录成功", map);
        } else {
            return Result.error("用户名或密码错误");
        }
    }


    @LogAnnotation(name = "用户名密码注册", description = "用户名密码注册，用户名不可相同")
    @Transactional
    @PostMapping("/register")
    public Result<?> register(@RequestBody RegisterDto in) throws Exception {
        User byUsername = userService.findByUsername(in.getUsername());
        if (byUsername != null) {
            return Result.error("用户名已存在");
        }
        User user = new User();
        user.setUsername(in.getUsername());
        user.setPassword(DigestUtil.md5Hex(RSAUtil.decrypted(in.getPassword())));
        userService.save(user);
        return Result.success("注册成功");
    }

    @LogAnnotation(name = "微信扫码登录注册", description = "微信扫码登录注册")
    @Transactional
    @PostMapping("/wxLogin")
    public Result<?> wxLogin(@RequestBody WxLoginDto in) {
        if (!webSocketService.isLoggingIn(in.getLoginCode())) {
            return Result.error("授权失败，二维码无效");
        }
        JSONObject data = wechatUtil.getSessionKeyOrOpenId(in.getCode());
        String openId = data.getString("openid");
        if (openId == null) {
            return new Result<>(data.getInteger("errcode"), data.getString("errmsg"));
        }

        User user = userService.findByOpenid(openId);

        //用户不存在  注册
        if (user == null) {
            user = new User();
            user.setOpenid(openId);
            user.setRole("用户");
            user.setUsername(in.getUsername());
            user.setAvatar(in.getAvatar());
            userService.save(user);
        } else {
            //用户存在
            user.setUsername(in.getUsername());
            user.setAvatar(in.getAvatar());
            userService.updateById(user);
        }


        String token = JWTUtil.generateToken(user);
        String refreshToken = UUID.randomUUID().toString();
        redisService.setRefreshToken(token, refreshToken, in.getUsername());
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("token", token);
        hashMap.put("refreshToken", refreshToken);
        hashMap.put("userInfo", user);

        webSocketService.loginSuccess(in.getLoginCode(),user, Result.success("WS登录成功", hashMap));
        return Result.success("授权成功");
    }

    @LogAnnotation(name = "邮箱登录注册", description = "邮箱登录注册")
    @Transactional
    @PostMapping("/emailLogin")
    public Result<?> emailLogin(@RequestBody EmailLoginDto in) {

        Result<?> result = redisService.verifyVerificationCode(in.getEmail(), in.getCode());
        if (result.getCode() == 1) {
            return result;
        }
        User user = userService.findByEmail(in.getEmail());

        //用户不存在  注册
        if (user == null) {
            user = new User();
            user.setRole("用户");
            user.setUsername(in.getEmail());
            user.setEmail(in.getEmail());
            userService.save(user);
        }

        String token = JWTUtil.generateToken(user);
        String refreshToken = UUID.randomUUID().toString();
        redisService.setRefreshToken(token, refreshToken, user.getUsername());
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("token", token);
        hashMap.put("refreshToken", refreshToken);
        hashMap.put("userInfo", user);
        return Result.success("登录成功", hashMap);
    }

    @LogAnnotation(name = "忘记密码", description = "忘记密码")
    @Transactional
    @PostMapping("/forget")
    public Result<?> forget(@RequestBody ForgetDto in) throws Exception {
        Result<?> result = redisService.verifyVerificationCode(in.getEmail(), in.getCode());
        if (result.getCode() == 1) {
            return result;
        }
        User user = userService.findByEmail(in.getEmail());
        if(user==null){
            return Result.error("邮箱不存在");
        }
        user.setPassword(DigestUtil.md5Hex(RSAUtil.decrypted(in.getPassword())));
        userService.updateById(user);
        return Result.success("重置成功");
    }

    @LogAnnotation(name = "用户注销", description = "用户注销 移出已登录websocket列表")
    @Transactional
    @PostMapping("/logout")
    public Result<?> logout(@RequestHeader("authorization") String token) {
        redisService.addBlackList(token);
        User user = JWTUtil.getUser(token);
//        webSocketService.removeOnline(user);
        return Result.success("登出成功");
    }

    @LogAnnotation(name = "获取签到日历", description = "根据Token获取签到日历")
    @Transactional
    @PostMapping("getSignedInDayByToken")
    public Result<?> getSignedInDay(@RequestHeader(value = "Authorization") String token) {
        String username = JWTUtil.getUsername(token);
        String signedInDay = redisService.getSignedInDay(username).replaceAll("^,+|,+$", "");
        return Result.success("操作成功", signedInDay);
    }

    @LogAnnotation(name = "今日签到", description = "根据Token今日签到")
    @Transactional
    @PostMapping("signeInByToken")
    public Result<?> signeIn(@RequestHeader(value = "Authorization") String token) {
        String username = JWTUtil.getUsername(token);
        return redisService.signeIn(username);
    }

    @LogAnnotation(name = "获取用户信息", description = "根据Token获取用户信息")
    @Transactional
    @PostMapping("userinfoByToken")
    public Result<?> userinfo(@RequestHeader(value = "Authorization") String token) {
        String username = JWTUtil.getUsername(token);
        User byUsername = userService.findByUsername(username);
        return Result.success(byUsername);
    }

    @LogAnnotation(name = "更新用户信息", description = "根据ID更新用户信息")
    @Transactional
    @PostMapping("updateUserInfo")
    public Result<?> updateUserInfo(@RequestBody @Validated UserUpdateDto in) {
        User byUsername = userService.findByUsername(in.getUsername());
        if (byUsername != null) {
            return Result.error("用户名已存在");
        }
        User user = JSONObject.parseObject(JSON.toJSONString(in), User.class);
        boolean b = userService.updateById(user);
        return Result.success("修改成功", user);
    }



    @LogAnnotation(name = "查询文章列表", description = "分页查询文章列表")
    @Transactional
    @PostMapping("queryList")
    public Result<?> queryList(@RequestBody @Validated QueryListDto in) {
        IPage<User> categoryIPage = userService.queryList(in);
        return Result.success(categoryIPage);
    }

}
